#ifndef MARCHINGCUBES_H_
#define MARCHINGCUBES_H_

#include "math/Vec3.h"
#include <list>

using std::list;

#include "Mesh.h"
class SpatialData;


class MarchingCubes {
public:
	MarchingCubes(SpatialData *data = 0);

	void setSpatialData(SpatialData *data);
	SpatialData* getSpatialData();

	Mesh* generateMesh(int xRes, int yRes, int zRes, float threshold);

	class Node {
	public:
		Node(){
		}

		Node(const Vec3 &pos, float val)
		:	position(pos), value(val)
		{
		}

		Vec3 position;
		float value;
	};

	class Cube {
	public:
		Cube(const Node &n0, const Node &n1, const Node &n2, const Node &n3, const Node &n4, const Node &n5, const Node &n6, const Node &n7){
			vertices[0] = n0;
			vertices[1] = n1;
			vertices[2] = n2;
			vertices[3] = n3;
			vertices[4] = n4;
			vertices[5] = n5;
			vertices[6] = n6;
			vertices[7] = n7;
		}

        void handleCase(float threshold, Mesh *m);
        void handleSubCase0(float threshold, int caseindex, Mesh *m);
        void handleSubCase1(float threshold, int caseindex, Mesh *m);
        void handleSubCase2(float threshold, int caseindex, Mesh *m);
        void handleSubCase3(float threshold, int caseindex, Mesh *m);
        void handleSubCase4(float threshold, int caseindex, Mesh *m);
        void handleSubCase5(float threshold, int caseindex, Mesh *m);
        void handleSubCase6(float threshold, int caseindex, Mesh *m);
        void handleSubCase7(float threshold, int caseindex, Mesh *m);
        void handleSubCase8(float threshold, int caseindex, Mesh *m);
        void subCase0(int i, int j, int k, int l, float threshold, Mesh *m);
        void subCase1(int i, int j, int k, int l, int m, int n, float threshold, Mesh *mesh);
        void subCase2(int i, int j, int k, int l, int m, int n, int o, int p, float threshold, Mesh *mesh);
        void subCase31(int i, int j, int k, int l, int m, int n, int o, float threshold, Mesh *mesh);
        void subCase32(int i, int j, int k, int l, int m, int n, int o, float threshold, Mesh *mesh);
        void subCase4(int i, int j, int k, int l, int m, int n, int o, int p, float threshold, Mesh *mesh);
        void subCase5(int i, int j, int k, int l, int m, int n, int o, int p, int q, int r, float threshold, Mesh *mesh);
        void subCase61(int i, int j, int k, int l, int m, int n, int o, float threshold, Mesh *mesh);
        void subCase62(int i, int j, int k, int l, int m, int n, int o, float threshold, Mesh *mesh);
        void subCase71(int i, int j, int k, int l, int m, int n, int o, int p, float threshold, Mesh *mesh);
        void subCase72(int i, int j, int k, int l, int m, int n, int o, int p, float threshold, Mesh *mesh);
        void subCase81(int i, int j, int k, int l, int m, int n, int o, int p, float threshold, Mesh *mesh);
        void subCase82(int i, int j, int k, int l, int m, int n, int o, int p, float threshold, Mesh *mesh);
        Vec3 interpolate(int i, int j, float threshold);
        //TODO private:
        int findCase(float threshold);

		Node vertices[8];
	};
private:
	Cube getCube(int xRes, int yRes, int zRes, int i, int j, int k);

    //Mesh *mesh;
	SpatialData *data;
};

#endif /* MARCHINGCUBES_H_ */
